
(function ($, win, doc, body) {
  function onResetFocus (evt) {
    $(body).unbind('click', onResetFocus);
    $('div.tmcombobox-container').removeClass('selected');
  }

  function onBodyClick (evt) {
    $(body).unbind('click', onBodyClick);
    $('div.tmcombobox-container').removeClass('showed-options').find('div.combobox-container:first').hide();
  }

  function onSelectFocus (evt, needTitleClick) {
		if (needTitleClick !== false) {
			onComboboxTitleClick(evt);
		}
		$(evt.target).parents('div.tmcombobox-container:first').addClass('selected');

    $(body).unbind('click', onResetFocus);
    setTimeout(bindResetFocus, 1);
  }

  function onSelectChange (evt) {
    
  }

  function onSelectKeyPress (evt) {
    switch (evt.keyCode) {
      case 9  :   //tab
        onBodyClick();
        onResetFocus();
        break;
      case 38 :   //up
        break;
      case 40 :   //down
        break;
    }
  }

	function onComboboxClick (evt) {
		$(this).find('select').trigger('focus', [false]);
	}

  function onComboboxTitleClick (evt) {
    var $combobox = $(evt.target).parents('div.tmcombobox-container:first');
    if ($combobox.hasClass('showed-options')) {
      return undefined;
    }

    onBodyClick(evt);
    $combobox.addClass('showed-options').find('div.combobox-container:first').show();
    setTimeout(bindBodyEvents, 1);
  }

  function onComboboxOptionClick (evt) {
    var $combobox = $(evt.target).parents('div.tmcombobox-container:first');
  }

  function bindResetFocus () {
    $(body).one('click', onResetFocus);
  }

  function bindBodyEvents () {
    $(body).one('click', onBodyClick);
  }
  function bindSelectEvents ($select, $combobox) {
    $select
      .focus(onSelectFocus)
      .change(onSelectChange)
      .keypress(onSelectKeyPress);
		$combobox.click(onComboboxClick);
    $combobox.find('div.combobox-title:first').click(onComboboxTitleClick);
    $combobox.find('ul.combobox-options:first').click(onComboboxOptionClick);

    return $select;
  }

  function renderCombobox (select, options) {
    var
      html = [],
      option = null,
      optionsvalue = [],
      selectclassname = select.className,
      selectoptionInd = -1,
      selectoption = null;

    if (!select) {
      return undefined;
    }

    for (var i = 0, n = options.length; i < n; i++) {
      option = options[i];
      if (option.selected === true) {
        selectoptionInd = i;
        selectoption = option;
      }
      optionsvalue.push(option.value);
      html = html.concat([
        '<li',
          ' class="option-item',
            option.classname ? ' ' + option.classname : '',
            option.selected === true ? ' selected-item' : '',
          '"',
          ' data-value="' + (optionsvalue.length - 1) + '"',
          ' title="' + option.title + '"',
        '>',
        option.title,
        '</li>'
      ]);
    }

    html = [
      '<div class="combobox-title">',
        selectoption.title,
      '</div>',
      '<div class="combobox-wrapper">',
        '<div class="combobox-container">',
          '<ul class="combobox-options">',
            html.join(''),
          '</ul>',
        '</div>',
      '</div>'
    ];

    var container = doc.createElement('div');
    container.className = 'tmcombobox-container' + (selectoptionInd !== -1 ? ' select-value-' + selectoptionInd : '') + (selectclassname ? ' ' + selectclassname : '');
    container.innerHTML = html.join('');

    var
      optionsvalueLen = optionsvalue.length,
      value = null,
      node = null,
      nodes = container.getElementsByTagName('li'),
      nodesInd = 0;
    nodesInd = nodes ? nodes.length : 0;
    while (nodesInd--) {
      node = nodes[nodesInd];
      value = node.getAttribute('data-value');
      value = isFinite(+value) ? +value : -1;
      if (value > -1 && value < optionsvalueLen) {
        node.setAttribute('data-value', optionsvalue[value]);
      }
    }

    return container;
  }

  function updateSelect ($o) {
    var
      select = $o.length > 0 ? $o[0] : null,
      selectvalue = select.value,
      opts = [],
      optionvalue = null,
      options = null,
      optionsInd = 0,
      option = null;

    if (!select) {
      return $o;
    }

    options = select.getElementsByTagName('option');
    optionsInd = options ? options.length : 0;
    while (optionsInd--) {
      option = options[optionsInd];
      optionvalue = option.getAttribute('value');
      opts.unshift({classname : option.className, value : optionvalue, title : option.innerHTML, selected : optionvalue == selectvalue});
    }

    var container = renderCombobox(select, opts);
    if (container) {
      select.parentNode.insertBefore(container, select);
      container.appendChild(select);
      container.setAttribute('data-value', selectvalue);
      return bindSelectEvents($(select), $(container));
    }
    return $o;
  }

  $.fn.tmCombobox = $.fn.tmcombobox = function () {
    var
      $this = $(this),
      $select = null,
      $selects = $this.filter('select'),
      selectsInd = 0;

    selectsInd = $selects.length;
    while (selectsInd--) {
      if (($select = $($selects[selectsInd])).hasClass('tmcombobox')) {
        continue;
      }
      updateSelect($select.addClass('tmcombobox'));
    }

    return $this;
  };
})(jQuery, window, document, document.body);
